package com.tensquare.notice.handler;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.tensquare.entity.Result;
import com.tensquare.entity.StatusCode;
import com.tensquare.notice.config.ApplicationContextProvider;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import org.springframework.amqp.core.DirectExchange;
import org.springframework.amqp.rabbit.core.RabbitAdmin;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

public class MyWebSocketHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {
    private static ObjectMapper MAPPER = new ObjectMapper();

    // 送Spring容器中获取消息监听器容器,处理订阅消息sysNotice
    SimpleMessageListenerContainer sysListenerContainer = (SimpleMessageListenerContainer) ApplicationContextProvider.getApplicationContext()
            .getBean("sysNoticeContainer");
    // 送Spring容器中获取消息监听器容器,处理订阅消息userNotice
    SimpleMessageListenerContainer userListenerContainer = (SimpleMessageListenerContainer) ApplicationContextProvider.getApplicationContext()
            .getBean("userNoticeContainer");

    //从Spring容器中获取RabbitTemplate
    RabbitTemplate rabbitTemplate = ApplicationContextProvider.getApplicationContext()
            .getBean(RabbitTemplate.class);

    //存放WebSocket连接Map，根据用户id存放
    public static ConcurrentHashMap<String, Channel> userChannelMap = new ConcurrentHashMap<>();

    //用户请求WebSocket服务端，执行的方法
    @Override
    protected void channelRead0(ChannelHandlerContext channelHandlerContext, TextWebSocketFrame msg) throws Exception {
        System.out.println("有用户发送消息到服务器：" + msg.text() + ".");
        //约定用户第一次请求携带的数据：{"userId":"1"}
        //获取用户请求数据并解析
        String json = msg.text();
        //解析json数据，获取用户id
        JsonNode jsonNode = MAPPER.readTree(json);
        JsonNode userIdNode = jsonNode.get("userId");
        String userId = null;
        Channel channel = null;
        if (!userIdNode.isNull()) {
            userId = userIdNode.asText();
            channel = userChannelMap.get(userId);
        }
        Result result;
        //第一次请求的时候，需要建立WebSocket连接
        if (channel == null && userId != null) {
            //获取WebSocket的连接
            channel = channelHandlerContext.channel();
            //把连接放到容器中
            userChannelMap.put(userId, channel);
        }

        if (userIdNode.isNull()) {
            assert channel != null;
            result = new Result(false, "入参异常", StatusCode.ERROR);
            channel.writeAndFlush(new TextWebSocketFrame(MAPPER.writeValueAsString(result)));
            return;
        }
        System.out.println("用户列表：" + userChannelMap.toString());
        //只用完成新消息的提醒即可，只需要获取消息的数量
        //获取RabbitMQ的消息内容，并发送给用户
        RabbitAdmin rabbitAdmin = new RabbitAdmin(rabbitTemplate);
        //拼接获取队列名称，
        String queueName = "article_subscribe_" + userId;
        //获取Rabbit的Properties容器
        Properties queueProperties = rabbitAdmin.getQueueProperties(queueName);

        //获取消息数量
        int noticeCount = 0;
        //判断Properties是否不为空
        if (queueProperties != null) {
            // 如果不为空，获取消息的数量
            noticeCount = (int) queueProperties.get("QUEUE_MESSAGE_COUNT");
        }
        /*else {
            assert channel != null;
            result = new Result(false, "请求队列不存在", StatusCode.ERROR);
            channel.writeAndFlush(new TextWebSocketFrame(MAPPER.writeValueAsString(result)));
            return;
        }*/

        //----------------------------------------------------------------
        //用户点赞的队列
        String userQueueName = "article_thumbup_" + userId;
        Properties thQueueProperties = rabbitAdmin.getQueueProperties(userQueueName);
        int userNoticeCount = 0;
        if (null != thQueueProperties) {
            userNoticeCount = (int) thQueueProperties.get("QUEUE_MESSAGE_COUNT");
        }

        //封装返回的数据
        HashMap<String, Object> countMap = new HashMap<>();
        countMap.put("sysNoticeCount", noticeCount);
        countMap.put("userNoticeCount", userNoticeCount);
        result = new Result(true, "查询成功", StatusCode.OK, countMap);
        //把数据发送给用户
        assert channel != null;
        channel.writeAndFlush(new TextWebSocketFrame(MAPPER.writeValueAsString(result)));

        //把消息从队列里面清空，否则MQ消息监听器会再次消费一次
        if (noticeCount > 0) {
            rabbitAdmin.purgeQueue(queueName, true);
        }

        if (userNoticeCount > 0) {
            rabbitAdmin.purgeQueue(userQueueName, true);
        }

        //为用户的消息通知队列注册监听器，便于用户在线的时候，
        //一旦有消息，可以主动推送给用户，不需要用户请求服务器获取数据
        String[] sysQueueNames = sysListenerContainer.getQueueNames();
        ArrayList<String> sysQueueList = new ArrayList<>(Arrays.asList(sysQueueNames));
        String[] userQueueNames = userListenerContainer.getQueueNames();
        ArrayList<String> userQueueList = new ArrayList<>(Arrays.asList(userQueueNames));
        if (queueProperties != null && !sysQueueList.contains(queueName)) {
            sysListenerContainer.addQueueNames(queueName);
        }

        if (thQueueProperties != null && !userQueueList.contains(userQueueName)) {
            userListenerContainer.addQueueNames(userQueueName);
        }

    }

    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
        removeUserAndQM(ctx.channel());
        System.out.println("用户列表：" + userChannelMap.toString());
        super.handlerRemoved(ctx);
    }

    /**
     * 把下线的用户移除队列
     *
     * @param channel
     */
    public void removeUserAndQM(Channel channel) {
        ConcurrentHashMap.KeySetView<String, Channel> keys = userChannelMap.keySet();
        for (String key : keys) {
            Channel userChannel = userChannelMap.get(key);
            if (channel.id() == userChannel.id()) {
                System.out.println("用户：" + key + "连接断开...");
                userChannelMap.remove(key);
                break;
            }
        }
    }

}
